package validate

import (
	"encoding/json"
	"github.com/BurntSushi/toml"
	"github.com/go-playground/locales"
	"github.com/go-playground/locales/en"
	"github.com/go-playground/locales/pt_BR"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	govalidator "github.com/go-playground/validator/v10"
	"github.com/nicksnyder/go-i18n/v2/i18n"
	"gopkg.in/yaml.v3"
	"io/ioutil"
	"os"
	"strings"
)

var unMap = map[string]i18n.UnmarshalFunc{
	"json": json.Unmarshal,
	"toml": toml.Unmarshal,
	"yaml": yaml.Unmarshal,
}

// NewTranslator 创建翻译器
func NewTranslator(supportedLocales ...locales.Translator) *Translator {
	supportedLocales = append(supportedLocales, zh.New(), en.New(), pt_BR.New())

	t := &Translator{
		validator:                govalidator.New(),
		uniTrans:                 ut.New(en.New(), supportedLocales...),
		translators:              supportedLocales,
		registerTranslationsFunc: defaultRegisterTranslationsFunc,
	}
	t.InitTranslator()
	return t
}

type Translator struct {
	validator                *govalidator.Validate
	uniTrans                 *ut.UniversalTranslator
	translators              []locales.Translator
	registerTranslationsFunc map[string]RegisterTranslationsFunc
}

func (t *Translator) InitTranslator() {
	for _, translator := range t.translators {
		t.RegisterDefaultTranslations(translator)
	}
}

// Validator 获取验证器
func (t *Translator) Validator() *govalidator.Validate {
	return t.validator
}

// UniversalTranslator 获取通用翻译管理器
func (t *Translator) UniversalTranslator() *ut.UniversalTranslator {
	return t.uniTrans
}

// GetTranslator 获取翻译器
func (t *Translator) GetTranslator(locale string) (ut.Translator, bool) {
	return t.uniTrans.GetTranslator(locale)
}

// SetRegisterTranslations 设置翻译函数
func (t *Translator) SetRegisterTranslations(m map[string]RegisterTranslationsFunc) {
	t.registerTranslationsFunc = m
}

// RegisterValidation 注册验证器
func (t *Translator) RegisterValidation(tag string, fn govalidator.Func, callValidationEvenIfNull ...bool) {
	t.validator.RegisterValidation(tag, fn, callValidationEvenIfNull...)
}

// RegisterDefaultTranslations 绑定validate 翻译器
func (t *Translator) RegisterDefaultTranslations(translator locales.Translator) {
	trans, _ := t.uniTrans.GetTranslator(translator.Locale())
	if fn, ok := t.registerTranslationsFunc[translator.Locale()]; ok {
		err := fn(t.validator, trans)
		if err != nil {
			panic(err)
		}
	}
}

// RegisterTranslation 注册翻译
func (t *Translator) RegisterTranslation(tag string, registerFn govalidator.RegisterTranslationsFunc, translationFn govalidator.TranslationFunc) {
	for _, translator := range t.translators {
		trans, _ := t.uniTrans.GetTranslator(translator.Locale())
		t.validator.RegisterTranslation(tag, trans, registerFn, translationFn)
	}
}

// transI18nToValidate 将i18n的翻译注入validate
func (t *Translator) transI18nToValidate(m *i18n.MessageFile) {
	locale := strings.Replace(m.Tag.String(), "-", "_", -1)
	trans, _ := t.uniTrans.GetTranslator(locale)
	for _, msg := range m.Messages {
		trans.Add(msg.ID, msg.Other, false)
	}
	return
}

// LoadLangFromPath 递归加载语言文件 注入validate
func (t *Translator) LoadLangFromPath(path string) error {
	langFiles, err := os.ReadDir(path)
	if err != nil {
		return err
	}
	for _, langFile := range langFiles {
		langFilePath := path + "/" + langFile.Name()
		if !langFile.IsDir() {
			buf, err := ioutil.ReadFile(langFilePath)
			if err != nil {
				return err
			}
			m, err := i18n.ParseMessageFileBytes(buf, langFilePath, unMap)
			if err != nil {
				return nil
			}
			t.transI18nToValidate(m)
		} else {
			err = t.LoadLangFromPath(langFilePath)
			if err != nil {
				return err
			}
		}
	}
	return nil
}
